/**
 * 检查数据类型的辅助函数
 * @param {any} data 需要检查的数据
 * @returns {string} 返回数据类型
 */
function checkType(data) {
    if (Array.isArray(data)) {
        return 'array'; // 判断是否为数组
    }
    if (data === null) {
        return 'null'; // 判断是否为 null
    }
    return typeof data; // 返回其他类型（例如：'object'、'string'、'number' 等）
}

/**
 * @param {'GET'|'POST'|'PUT'|'DELETE'} method 请求方法
 * @param {string} url 请求路径
 * @param {object|FormData|string=} data 传参
 * @param {RequestInit & { timeout: number }} option 其他配置
 */
function fetchRequest(method, url, data = {}, option = {}) {
    let body = undefined;  // 非GET请求传参 
    let query = ""; //GET请求传参     
    const headers = {}; // 默认请求头    
    const timeout = option.timeout || 8000; // 超时毫秒   
    const dataType = checkType(data); // 传参数据类型

    // 处理 GET 请求的查询参数
    if (method === "GET") {
        if (dataType === "object") {
            const params = new URLSearchParams(data).toString();
            if (params) {
                query = `?${params}`;
                url += query;
            }
        } else {
            console.warn("fetch: GET 请求传参应为 object 类型");
        }
    } else {
        // 处理非 GET 请求的 body 内容
        if (dataType === "object" || dataType === "array") {
            body = JSON.stringify(data);
            headers["Content-Type"] = "application/json";
        } else if (dataType === "string") {
            body = data;
            headers["Content-Type"] = "application/x-www-form-urlencoded"; // URL-encoded
        }
    }

    // 如果传递的 data 是 FormData，则不需要 JSON 或 URL 编码
    if (data instanceof FormData) {
        body = data;
        delete headers["Content-Type"]; // FormData 不需要设置 Content-Type
    }

    const controller = new AbortController();
    let timer;

    return new Promise((resolve, reject) => {
        fetch(url, {
            method,
            body,
            headers,
            signal: controller.signal,
            ...option,
        })
        .then(response => {
            // 检查响应是否成功
            if (!response.ok) {
                return Promise.reject(`Error: ${response.statusText}`);
            }
            return response.json();
        })
        .then(res => {
            clearTimeout(timer);
            resolve(res);
        })
        .catch(error => {
            clearTimeout(timer);
            reject(error);
        });

        // 设置超时
        timer = setTimeout(() => {
            reject("fetch request timeout");
            controller.abort();
        }, timeout);
    });
}

// 异步请求并处理响应
async function fetchData(url, method = 'GET', data = {}) {
    try {
        const response = await fetchRequest(method, url, data);
        return response;
    } catch (error) {
        console.error(`Request failed: ${error}`);
        throw error; // 抛出错误，便于后续捕获
    }
}